<template>
  <v-menu
      v-model="show"
      :offset-y="true"
      :bottom="true"
      :close-on-content-click="false"
      max-height="500px"
  >
    <template #activator="{ attrs, on }">
      <v-text-field
          v-model="treeName"
          :label="props.label"
          :dense="props.dense"
          :solo="props.solo"
          :flat="props.flat"
          :readonly="!props.hasInputSearch || !props.items.length"
          :outlined="props.outlined"
          hide-details="auto"
          v-bind="attrs"
          :rules="props.rules"
          :disabled="props.disabled"
          class="input-field"
          :placeholder="props.disabled ? '' : defaultPlaceholder"
          @click:clear="onClear"
          v-on="on"
          :clearable="props.clearable"
      />
    </template>
    <v-card>
      <v-treeview
          v-if="!props.hasCheckBox"
          :active="value.value"
          :search="props.hasInputSearch ? treeName : empty"
          :filter="filter"
          :item-key="props.treeKey"
          :item-text="props.treeLabel"
          :item-children="props.treeChildrenKey"
          selection-type="independent"
          transition
          activatable
          :open-on-click="props.openOnClick"
          :items="props.items"
          selected-color="primary"
          @update:active="activeItem"
          :load-children="props.fetchChildren"
          :open="open"
      ></v-treeview>
      <v-treeview
          v-if="props.hasCheckBox"
          :value="value.value"
          :search="props.hasInputSearch ? treeName : empty"
          :filter="filter"
          :item-key="props.treeKey"
          :item-text="props.treeLabel"
          :item-children="props.treeChildrenKey"
          transition
          :open-on-click="props.openOnClick"
          :items="props.items"
          selectable
          selected-color="primary"
          @input="checkItem"
          :load-children="props.fetchChildren"
          :open="open"
      ></v-treeview>
    </v-card>
  </v-menu>
</template>
<script setup>
import {computed, defineModel, onMounted, reactive, ref, watch} from 'vue';

const emit = defineEmits(['change']);

const value = defineModel('value');
const change = defineModel('change');

const props = defineProps({
  rules: { type: Array, default: () => [] },
  items: { type: Array, default: () => [] },
  value: { type: [Array, null], default: () => [] },
  label: { type: String, default: '' },
  treeLabel: { type: String, default: 'name' }, // 树形显示名称
  treeKey: { type: String, default: 'id' }, // 树形唯一ID
  treeChildrenKey: { type: String, default: 'children' }, // 树形子集Key
  placeholder: { type: String, default: '' },
  labelWidth: { type: String, default: '100px' },
  inputWidth: { type: String, default: '200px' },
  disabled: { type: Boolean, default: false },
  readonly: { type: Boolean, default: false },
  openOnClick: { type: Boolean, default: false }, // 点选父级展开子项，父级不选
  hasCheckBox: { type: Boolean, default: false }, // 是否多选框
  hasInputSearch: { type: Boolean, default: true }, // 是否模糊搜索
  clearable: { type: Boolean, default: false },
  outlined: { type: Boolean, default: false },
  solo: { type: Boolean, default: false },
  dense: { type: Boolean, default: false },
  flat: { type: Boolean, default: false },
  fetchChildren: { type: Function, default: null },
})

const empty = ref('');
const show = ref(false);
const selection = ref([]);
const checkName = ref([]);
const checkId = ref([]);
const tree = reactive([]);
const treeName = ref(null);
const treeData = reactive([]);
const open = reactive([]);

const filter = computed(() => (item, search, textKey) => item[textKey].indexOf(search) > -1);
const defaultPlaceholder = computed(() => props.placeholder === '' ? '' : props.placeholder);
const cssVars = computed(() => {
  return {
    '--labelWidth': props.labelWidth,
    '--inputWidth': props.inputWidth,
  };
});

const showName = (data, parentName, parentId = []) => {
  const treeData = selection.value || [];
  const label = props.treeLabel;
  const value = props.treeKey;
  const children = props.treeChildrenKey;
  data.map((item) => {
    if (treeData.includes(item[value])) {
      if (!checkName.value.includes(item[label])) {
        checkName.value.push(parentName ? `${parentName}/${item[label]}` : `${item[label]}`);
        checkId.value = parentId.length ? parentId.concat(item[value]) : [].concat(item[value]);
      }
    } else if (item[children]?.length) {
      showName(
          item[children],
          parentName ? `${parentName}/${item[label]}` : `${item[label]}`,
          parentId.length ? parentId.concat(item[value]) : [].concat(item[value]),
      );
    }
  });
  treeName.value = checkName.value.toString();
};

watch(value, (newVal, oldVal) => {
  selection.value = newVal;
  checkName.value = [];
  checkId.value = [];
  showName(props.items);
}, {immediate: true});

onMounted(() => emit('change', value));

const activeItem = (val) => {
  treeName.value = null;
  checkName.value = [];
  checkId.value = [];
  selection.value = val;
  showName(props.items);
  if (val.length > 0) {
    setTimeout(() => {
      this.show = false;
    }, 500);
  }
  this.$emit('change', val);
};

const checkItem = (val) => {
  treeName.value = null;
  checkName.value = [];
  checkId.value = [];
  selection.value = val;
  showName(props.items);
  // if (val.length > 0) {
  //   setTimeout(() => {
  //     this.show = false;
  //   }, 500);
  // }
  emit('change', val);
};
const onClear = () => {
  treeName.value = null;
  checkName.value = [];
  checkId.value = [];
  selection.value = [];
  emit('change', []);
};
</script>
<style lang="scss" scoped>
.input-field {
  width: var(--inputWidth);
}
.input-label {
  width: var(--labelWidth);
}
//让错误浮动的显示在入力框下面，并不占用页面空间。
//::v-deep .v-text-field__details {
//  position: absolute;
//  top: 3em;
//}

::v-deep .v-treeview-node__label {
  font-size: 14px;
}
</style>